package com.jingdianjichi.subject.domain.service.impl;

import com.alibaba.fastjson.JSON;
import com.jingdianjichi.subject.common.entity.PageResult;
import com.jingdianjichi.subject.common.enums.IsDeleteFlagEnum;
import com.jingdianjichi.subject.common.enums.SubjectLikedStatusEnum;
import com.jingdianjichi.subject.common.util.LoginUtil;
import com.jingdianjichi.subject.domain.convert.SubjectLikedBOConverter;
import com.jingdianjichi.subject.domain.entity.SubjectLikedBO;
import com.jingdianjichi.subject.domain.redis.RedisUtil;
import com.jingdianjichi.subject.domain.service.SubjectLikedDomainService;
import com.jingdianjichi.subject.infra.basic.entity.SubjectLiked;
import com.jingdianjichi.subject.infra.basic.service.SubjectLikedService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.MapUtils;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Objects;

/**
 * 点赞表 领域service实现了
 *
 * @author wuyimin
 * @since 2024-02-21 08:04:54
 */
@Service
@Slf4j
public class SubjectLikedDomainServiceImpl implements SubjectLikedDomainService {

    @Resource
    private SubjectLikedService subjectLikedService;

    @Resource
    private RedisUtil redisUtil;

    // 定义保存点赞状态的Redis键的前缀
    private static final String SUBJECT_LIKED_KEY = "subject.liked";

    // 定义保存点赞数量的Redis键的前缀
    private static final String SUBJECT_LIKED_COUNT_KEY = "subject.liked.count";

    // 定义保存点赞详情的Redis键的前缀
    private static final String SUBJECT_LIKED_DETAIL_KEY = "subject.liked.detail";

    @Override
    public void add(SubjectLikedBO subjectLikedBO) {
        // 获取题目ID
        Long subjectId = subjectLikedBO.getSubjectId();
        // 获取点赞用户ID
        String likeUserId = subjectLikedBO.getLikeUserId();
        // 获取点赞状态（比如，1表示点赞，0表示取消点赞）
        Integer status = subjectLikedBO.getStatus();

        // 构建保存点赞状态的Redis键，格式为"subject.liked:题目ID:点赞用户ID"
        String hashKey = buildSubjectLikedKey(subjectId.toString(), likeUserId);
        // 在Redis中更新点赞状态，保存或更新点赞用户对某题目的点赞状态
        redisUtil.putHash(SUBJECT_LIKED_KEY, hashKey, status);

        // 构建保存点赞详情的Redis键，格式为"subject.liked.detail.题目ID.点赞用户ID"
        String detailKey = SUBJECT_LIKED_DETAIL_KEY + "." + subjectId + "." + likeUserId;
        // 构建保存点赞数量的Redis键，格式为"subject.liked.count.题目ID"
        String countKey = SUBJECT_LIKED_COUNT_KEY + "." + subjectId;

        // 如果是点赞操作
        if (SubjectLikedStatusEnum.LIKED.getCode() == status) {
            // 点赞数量加1
            redisUtil.increment(countKey, 1);
            // 设置点赞详情标记为"1"
            redisUtil.set(detailKey, "1");
        } else {
            // 如果是取消点赞操作，首先获取当前点赞数量
            Integer count = redisUtil.getInt(countKey);
            // 如果点赞数量为null或小于等于0，就直接返回，不做处理
            if (Objects.isNull(count) || count <= 0) {
                return;
            }
            // 点赞数量减1
            redisUtil.increment(countKey, -1);
            // 删除点赞详情
            redisUtil.del(detailKey);
        }
    }

    // 构建保存点赞状态的Redis键，格式为"subject.liked:题目ID:点赞用户ID"
    private String buildSubjectLikedKey(String subjectId, String userId) {
        return subjectId + ":" + userId;
    }


    /**
     * 判断是否点赞
     * @param subjectId
     * @param userId
     * @return
     */
    @Override
    public Boolean isLiked(String subjectId, String userId) {
        // 构建用于存储点赞详情的Redis键，格式为"subject.liked.detail.题目ID.用户ID"
        String detailKey = SUBJECT_LIKED_DETAIL_KEY + "." + subjectId + "." + userId;
        // 检查Redis中是否存在该键，存在则表示用户已经对该题目点赞，否则没有点赞
        return redisUtil.exist(detailKey);
    }

    /**
     * 获取点赞数量
     * @param subjectId
     * @return
     */
    @Override
    public Integer getLikedCount(String subjectId) {
        // 构建用于存储点赞数量的Redis键，格式为"subject.liked.count.题目ID"
        String countKey = SUBJECT_LIKED_COUNT_KEY + "." + subjectId;
        // 从Redis中获取该题目的点赞数量
        Integer count = redisUtil.getInt(countKey);
        // 如果点赞数量为null或小于等于0，返回0，否则返回实际的点赞数量
        if (Objects.isNull(count) || count <= 0) {
            return 0;
        }
        return redisUtil.getInt(countKey);
    }



    @Override
    public Boolean update(SubjectLikedBO subjectLikedBO) {
        // 将业务对象（BO）转换为实体对象（Entity），这里使用了一个名为SubjectLikedBOConverter的转换器
        SubjectLiked subjectLiked = SubjectLikedBOConverter.INSTANCE.convertBOToEntity(subjectLikedBO);
        // 调用subjectLikedService的update方法更新点赞信息，如果更新操作影响的记录数大于0，则返回true，表示更新成功
        return subjectLikedService.update(subjectLiked) > 0;
    }


    @Override
    public Boolean delete(SubjectLikedBO subjectLikedBO) {
        // 创建点赞实体对象
        SubjectLiked subjectLiked = new SubjectLiked();
        // 设置要删除的点赞信息的ID
        subjectLiked.setId(subjectLikedBO.getId());
        // 设置删除标志为已删除状态
        subjectLiked.setIsDeleted(IsDeleteFlagEnum.DELETED.getCode());
        // 调用服务层的更新方法，实际上是逻辑删除，如果更新行数大于0，则返回true表示删除成功
        return subjectLikedService.update(subjectLiked) > 0;
    }


    /**
     * 查询我的点赞列表
     * @param subjectLikedBO 点赞业务对象，包含查询条件
     * @return 分页查询结果，包含点赞列表和其他分页信息
     */
    @Override
    public PageResult<SubjectLikedBO> getSubjectLikedPage(SubjectLikedBO subjectLikedBO) {
        // 创建分页结果对象
        PageResult<SubjectLikedBO> pageResult = new PageResult<>();
        // 设置当前页号
        pageResult.setPageNo(subjectLikedBO.getPageNo());
        // 设置每页显示记录数
        pageResult.setPageSize(subjectLikedBO.getPageSize());
        // 计算查询的起始位置
        int start = (subjectLikedBO.getPageNo() - 1) * subjectLikedBO.getPageSize();
        // 将业务对象转换为实体对象
        SubjectLiked subjectLiked = SubjectLikedBOConverter.INSTANCE.convertBOToEntity(subjectLikedBO);
        // 设置当前登录用户的ID为点赞人ID
        subjectLiked.setLikeUserId(LoginUtil.getLoginId());
        // 根据条件查询点赞数量
        int count = subjectLikedService.countByCondition(subjectLiked);
        // 如果数量为0，直接返回空的分页结果
        if (count == 0) {
            return pageResult;
        }
        // 分页查询点赞列表
        List<SubjectLiked> subjectLikedList = subjectLikedService.queryPage(subjectLiked, start,
                subjectLikedBO.getPageSize());
        // 将实体列表转换为业务对象列表
        List<SubjectLikedBO> subjectInfoBOS = SubjectLikedBOConverter.INSTANCE.convertListInfoToBO(subjectLikedList);

        // 设置分页结果中的记录列表
        pageResult.setRecords(subjectInfoBOS);
        // 设置总记录数
        pageResult.setTotal(count);
        // 返回分页结果
        return pageResult;
    }

    /**
     * 同步点赞数据
     */
    @Override
    public void syncLiked() {
        // 从Redis中获取所有点赞信息并同时删除这些信息，避免重复处理
        Map<Object, Object> subjectLikedMap = redisUtil.getHashAndDelete(SUBJECT_LIKED_KEY);

        // 如果开启了信息级别的日志，则记录点赞信息的日志
        if (log.isInfoEnabled()) {
            log.info("syncLiked.subjectLikedMap:{}", JSON.toJSONString(subjectLikedMap));
        }

        // 如果从Redis获取的点赞信息为空，则直接返回，不进行后续操作
        if (MapUtils.isEmpty(subjectLikedMap)) {
            return;
        }

        // 准备一个列表，用于存放需要批量插入到数据库中的点赞实体对象
        List<SubjectLiked> subjectLikedList = new LinkedList<>();

        // 遍历从Redis中获取的点赞信息
        subjectLikedMap.forEach((key, val) -> {
            // 创建点赞实体对象
            SubjectLiked subjectLiked = new SubjectLiked();
            // 由于Redis中保存的key为"题目ID:点赞用户ID"的格式，这里将其拆分
            String[] keyArr = key.toString().split(":");
            String subjectId = keyArr[0]; // 题目ID
            String likedUser = keyArr[1]; // 点赞用户ID
            // 设置点赞实体的属性值
            subjectLiked.setSubjectId(Long.valueOf(subjectId)); // 设置题目ID
            subjectLiked.setLikeUserId(likedUser); // 设置点赞用户ID
            subjectLiked.setStatus(Integer.valueOf(val.toString())); // 设置点赞状态
            subjectLiked.setIsDeleted(IsDeleteFlagEnum.UN_DELETED.getCode()); // 设置删除标志（未删除）
            // 将点赞实体添加到列表中
            subjectLikedList.add(subjectLiked);
        });

        // 调用服务层方法，批量将点赞信息插入到数据库中
        subjectLikedService.batchInsert(subjectLikedList);
    }

}

